module AlohaP
{

	//Radio
	provides interface AlohaSend;
	provides interface AlohaReceive;
	provides interface AlohaState;

	//Low Level radio
	uses interface RadioSend as MulleSend;
	uses interface RadioReceive as MulleReceive;
	uses interface RadioState as MulleState;
	uses interface Packet;
	uses interface AMPacket;

	//Timers
	uses interface Timer<TMilli> as Timer0;

	//Other
	uses interface Leds;

}
implementation {
	//General info
	uint8_t g_channel = -1;
	norace uint8_t g_state = STATE_READY;
	
	
	uint16_t g_counter = 0;
	
	am_addr_t g_AM_Addr = 1;
	am_group_t g_AM_Group = 1;
	am_id_t g_AM_ID_TYPE = 0;

	event void Timer0.fired() 
	{
		#ifdef D7015E_DEBUG_ALOHAC
		printf("|%d|-----|-----|AlohaP::fired() [%d]\n", TOS_NODE_ID, g_state);
		printfflush();
		#endif	
	}



   

	/**************************************************************************
	 * 
	 * 			AlohaSend interface
	 * 
	 * 
	 **************************************************************************/ 
	 

	


	// Many EBUSY replies from RadioSend are normal if the channel is cognested
	enum { MAX_RETRIES = 5 };
	message_t* txMsg;
	error_t txError;
	uint8_t retries;
	
	
	task void sendTask()
	{
		error_t error;

		atomic error = txError;
		
		if(g_state == STATE_TX_SEND && error == SUCCESS)
			g_state = STATE_TX_DONE;
		
		if (g_state == STATE_TX_PENDING)
		{
			error = call MulleSend.send(txMsg);
			if( error == SUCCESS )
				g_state = STATE_TX_SEND;
			else
				g_state = STATE_TX_PENDING;
		}
				
		if( g_state == STATE_TX_DONE )
		{
			g_state = STATE_READY;
			signal AlohaSend.sendDone(error);
		}
	}
	/**
	 * Signals the completion of the send command, exactly once for each 
	 * successfull send command. If the returned error code is SUCCESS, then 
	 * the message was sent (may not have been acknowledged), otherwise 
	 * the message was not transmitted over the air.
	 */

	tasklet_async event void MulleSend.sendDone(error_t error) 
	{
		atomic txError = error;
		post sendTask();
	}

	/**
	 * This event is fired when the component is most likely able to accept 
	 * a send request. If the send command has returned with a failure, then
	 * this event will be called at least once in the near future.
	 */ 

	tasklet_async event void MulleSend.ready() 
	{
		if( g_state == STATE_TX_PENDING )
			post sendTask();
	}

	



	command error_t AlohaSend.send(message_t * msg, am_addr_t destination) 
	{
		if( g_state != STATE_READY )
			return FAIL;
		
		call AMPacket.setSource(msg, call AMPacket.address());
		call AMPacket.setDestination(msg, g_AM_Addr);

		call AMPacket.setGroup(msg, call AMPacket.localGroup());
		call AMPacket.setType(msg, g_AM_ID_TYPE);

		call Packet.setPayloadLength(msg, sizeof(myMsg_t));
		
		txMsg = msg;
		g_state = STATE_TX_PENDING;
		//retries = 0;
		post sendTask();

		return SUCCESS;
	}



	command error_t AlohaSend.cancel(message_t* msg)
	{
	/*	if( g_state == STATE_TX_PENDING )
		{
			g_state = STATE_READY;

			// TODO: check if sendDone can be called before cancel returns
			signal AlohaSend.sendDone(msg, ECANCEL);

			return SUCCESS;
		}
		else
			return FAIL;*/
	}
	//event void sendDone(error_t error);     

	/***************************************************************************
	 * 
	 * 			RadioReceive interface
	 * 
	 * 
	 **************************************************************************/
	/**
	 * This event is fired when the header is received/downloaded and the 
	 * higher layers are consulted whether it needs to be downloaded and 
	 * further processed. Return FALSE if the message should be discarded.
	 * In particular, the message buffer layer returns FALSE if there is
	 * no space for a new message, so this message will not get acknowledged.
	 */
	tasklet_async event bool MulleReceive.header(message_t * msg) {
		return true;
	}

	/**
	 * Signals the reception of a message, but only for those messages for
	 * which SUCCESS was returned in the header event. The usual owner rules 
	 * apply to the message pointers.
	 */
/*	task void t_notifyReceived() {
		atomic g_state = STATE_TURN_ON;
	    signal AlohaReceive.receiveDone(pkt2, SUCCESS);
	}
*/
	tasklet_async event message_t * MulleReceive.receive(message_t * msg) {
/*
		myMsg_t * temp_msg = (myMsg_t * ) msg;
		#ifdef D7015E_DEBUG_ALOHAC
		printf("|%d|-----|-----|AlohaP::MulleReceive.receive() [%d]\n", TOS_NODE_ID,
				g_state);
		printf("|%d|-----|-----|txMsg:: uid [%d]\n", TOS_NODE_ID, temp_msg->uid);
		printf("|%d|-----|-----|txMsg:: counter [%d]\n", TOS_NODE_ID, temp_msg->counter);
		printf("|%d|-----|-----|txMsg:: myData [%d]\n",TOS_NODE_ID,temp_msg->myData);
		printfflush();
		#endif	
		//call Leds.led1Toggle();
		
		atomic pkt2 = msg;
		post t_notifyReceived();	*/
	}

	/***************************************************************************
	 * 
	 * 			AlohaReceive interface
	 * 
	 * 
	 **************************************************************************/ 

	task void t_AlohaReceive_receive() 
	{

	}
	
	command error_t AlohaReceive.receive() 
	{

			return FAIL;
		
	}

	

	/***************************************************************************
	 * 
	 * 			RadioState interface
	 * 
	 * 
	 **************************************************************************/
	norace uint8_t state;	// written only from tasks


	command error_t AlohaState.start()
	{
		error_t error;

		if( state != STATE_READY )
			error = EBUSY;
		else
			error = call MulleState.turnOn();

		if( error == SUCCESS )
			state = STATE_TURN_ON;
			
		return error;
	}
	
	command error_t AlohaState.stop()
	{
		error_t error;

		if( state != STATE_READY )
			error = EBUSY;
		else
			error = call MulleState.turnOff();

		if( error == SUCCESS )
			state = STATE_TURN_OFF;
		return error;
	}
//range of channel ???
	command error_t AlohaState.setChannel(uint8_t channel)
	{
		error_t error;

		if( state != STATE_READY )
			error = EBUSY;
		else
			error = call MulleState.setChannel(channel);

		if( error == SUCCESS )
			state = STATE_CHANNEL;
		return error;
	}

	command uint8_t AlohaState.getChannel()
	{
		return call MulleState.getChannel();
	}

	task void stateDoneTask()
	{
		uint8_t s;
		
		s = state;

		// change the state before so we can be reentered from the event
		state = STATE_READY;

		if( s == STATE_TURN_ON )
			signal AlohaState.startDone(SUCCESS);
		else if( s == STATE_TURN_OFF )
			signal AlohaState.stopDone(SUCCESS);
		else if( s == STATE_CHANNEL )
			signal AlohaState.setChannelDone(SUCCESS);
		else	// not our event, ignore it
			state = s;
	}

	tasklet_async event void MulleState.done()
	{
		post stateDoneTask();
	}
   

}